package tests.components.maincomponent;

/**
 * @author Philipp Hannemann & Christoph Lehnert
 */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

import org.bonn.ooka.core.EScope;
import org.bonn.ooka.core.Inject;
import org.bonn.ooka.model.EState;
import org.bonn.ooka.model.IComponent;
import org.bonn.ooka.model.IComponentAssembler;
import org.bonn.ooka.model.Observable;
import org.bonn.ooka.model.Observer;
import org.bonn.ooka.model.start;
import org.bonn.ooka.model.update;

@Observer
@Observable
public class MainComponent implements IComponent {
	private IComponentAssembler holder = null;
	private IComponent subComp = null;
	private EScope scope = EScope.SCOPE_IN_PRODUCTION;

	@Inject
	public void setSubComp(IComponent subComp) {
		this.subComp = subComp;
	}

	@start
	public void start(IComponentAssembler holder, Object... params) {
		this.holder = holder;
		System.out.println("Starte");

		try {
			this.notifyObservers(EState.RUNNING);
		} catch (IllegalAccessException | IllegalArgumentException
				| InvocationTargetException | InstantiationException
				| NullPointerException e1) {
			System.out
					.println("TestClass.start(), ERROR while notifying observers: "
							+ Arrays.toString(e1.getStackTrace()));
		}
		subComp.start(holder, params);
	}

	@Override
	public void stop() {
		System.out.println("TestClass.stop()");
		try {
			this.notifyObservers(EState.STOPPED);
		} catch (IllegalAccessException | IllegalArgumentException
				| InvocationTargetException | InstantiationException
				| NullPointerException e1) {
			System.out
					.println("TestClass.start(), ERROR while notifying observers: "
							+ Arrays.toString(e1.getStackTrace()));
		}
	}

	private void notifyObservers(EState state) throws IllegalAccessException,
			IllegalArgumentException, InvocationTargetException,
			InstantiationException, NullPointerException {
		Map<String, IComponent> observables = this.holder.getObservers(this);
		for (IComponent comp : observables.values()) {
			Method[] methods = comp.getClass().getMethods();
			for (Method method : methods) {
				if (method.isAnnotationPresent(update.class)) {
					System.out
							.println("TestClass.notifyObservers(), Invoking method: "
									+ method.getName());
					method.invoke(comp, this, state);
				}
			}
		}
	}

	@update
	public void update(Object obj, EState state) {
		System.out.println("TestClass.update() (Hash: " + this.hashCode()
				+ ") recieved update by " + obj.getClass().getName()
				+ " (Hash: " + obj.hashCode() + "): " + state);
	}

	public EScope getScope() {
		return scope;
	}

	@Override
	public void setScope(EScope scope) {
		this.scope = scope;
	}
}